'use strict'
const LANG_FOLDER = 'zh_cn'

const fs = require('fs')
const crypto = require('crypto')
const path = require('path')

const VERSION_FILE_PATH = './versions'
var RESOURCE_ROOT = path.normalize('../../resource/')
var CFG_PATH = path.join(RESOURCE_ROOT, 'resource.json')

const PROCESS_ARGV = {v:0,r:'.'}

var _sheetMap = {};
var _newVMap = {};
var _oldVMap;
var _cfgObj;
var _hasCheckedAllFiles = false;

dealArgv();
main();

function dealArgv(){
    var pArgv = process.argv;
    var keys = Object.keys(PROCESS_ARGV);
    for( var i = keys.length - 1; i >= 0; i-- ){
        var key = keys[ i ];
        var cliKey = '-'+key;
        var cliIndex = pArgv.indexOf(cliKey)
        if(cliIndex>=0){
            PROCESS_ARGV[key] = pArgv[cliIndex+1]
        }
    }
}

function main(){
	RESOURCE_ROOT = path.join(PROCESS_ARGV.r,RESOURCE_ROOT);
	CFG_PATH = path.join(RESOURCE_ROOT, 'resource.json')
    readCfgFile();
    dealVersionFile();
}

function readCfgFile(){
    fs.readFile(CFG_PATH, 'utf-8', function(err, content){
        if(err){
            warn( err );
        }else{
            _cfgObj = JSON.parse( content );
            if(_hasCheckedAllFiles && _oldVMap){
                makeVersion();
            }
        }
    })
}

function readVersionFile(){
    fs.readFile(VERSION_FILE_PATH, 'utf-8', function(err, content){
        if(err){
            warn( err );
        }else{
            _oldVMap = JSON.parse( content );
            if(_hasCheckedAllFiles && _cfgObj){
                makeVersion();
            }
        }
    })
}


function dealVersionFile(){
    fs.stat(VERSION_FILE_PATH, function(vErr, vStat){
        if(vErr){
            _oldVMap = {};
        }else{
            readVersionFile();
        }
        walkResourceRoot();
    });
}

function finishFileCheck(cntObj){
    if(--cntObj[0]>0) return;
    _hasCheckedAllFiles = true;
    if(_cfgObj && _oldVMap){
        makeVersion();
    }
}

function makeVersion(){
    var keys = Object.keys(_newVMap)
    var newResList = [];
    for(var i=keys.length-1; i>=0; i--){
        var resUrl = keys[i];
        var pathObj = path.parse(resUrl);
        var noExtFullName = pathObj.dir+'/'+pathObj.name
        var fileType = getFileType(pathObj.ext)
        var isSheetChange = false;
        if(fileType == 'image'){//检查是否为贴图集
            var checkJsonPath = noExtFullName+'.json'
            if(_newVMap[checkJsonPath]){
                if(_sheetMap[noExtFullName]){
                    isSheetChange = checkMd5Change( resUrl ) || checkMd5Change( _sheetMap[ noExtFullName ] );
                    var newDsc = {name:pathObj.name, type:'sheet', url:_sheetMap[noExtFullName]}//sheet名字不带扩展名
                }else{
                    _sheetMap[noExtFullName] = resUrl;
                    continue;
                }
            }else{
                newDsc = getDescribeObj(resUrl, pathObj)
            }
        }else if(fileType == 'json'){
            var checkImgPath = noExtFullName+'.png'
            if(_newVMap[checkImgPath]){
                if(_sheetMap[noExtFullName]){
                    isSheetChange = checkMd5Change( resUrl ) || checkMd5Change( _sheetMap[ noExtFullName ] );
                    newDsc = {name:pathObj.name, type:'sheet', url:resUrl}//sheet名字不带扩展名
                }else{
                    _sheetMap[noExtFullName] = resUrl;
                    continue;
                }
            }else{
                newDsc = getDescribeObj(resUrl, pathObj );
            }
        }else{
            newDsc = getDescribeObj(resUrl, pathObj)
        }

        if(PROCESS_ARGV.v!=0) {
            addVersionToUrl( newDsc, PROCESS_ARGV.v );
        }else if(isSheetChange) {
            dealVersionChange(newDsc, getOldVersion(newDsc.name))
        }else{
            dealNewVersion( newDsc, resUrl );
        }
        var checkSameDsc = searchArr(newResList, 'name', newDsc.name)
        if(checkSameDsc){
            throw(new Error("repeat name!!!\n"+checkSameDsc.url+"\n"+newDsc.url))
        }
        newResList.push(newDsc)
    }
    _cfgObj.resources = newResList;
    writeFile( CFG_PATH, getOrderedResourceStr( _cfgObj ), 'resource cfg finish' );
    writeFile( VERSION_FILE_PATH, getOrderedObjStr( _newVMap ), 'version file finish' );
}

function checkMd5Change(resUrl){
    var oldMd5 = _oldVMap[resUrl]
    if(oldMd5 && oldMd5!=_newVMap[resUrl]){
        return true
    }
    return false
}

function dealNewVersion(newDsc, resUrl){
    var oldVersion = getOldVersion( newDsc.name );
    if(checkMd5Change(resUrl)){
        dealVersionChange(newDsc, oldVersion);
    }else if(oldVersion){
        newDsc.url += '?v='+oldVersion;
    }
}

function getOldVersion(desName){
    var oldVersion;
    var oldDsc = getDscFromList(_cfgObj.resources, desName);
    if(oldDsc){
        var vStrList = oldDsc.url.split('?v=')
        if(vStrList.length>1){
            oldVersion = vStrList.pop();
        }
    }
    return oldVersion;
}

function dealVersionChange(newDsc, oldVersion){
    var newVersion = 1;
    if(oldVersion){
        var ovStrList = oldVersion.split( '.' );
        var lastOvIndex = ovStrList.length - 1;
        ovStrList[lastOvIndex] = 1+parseInt(ovStrList[lastOvIndex]);
        newVersion = ovStrList.join('.')
    }
    addVersionToUrl( newDsc, newVersion );
}

function addVersionToUrl(newDsc, version){
    newDsc.url += '?v='+version;
}

function searchArr(arr, key, value){
    for(var i=arr.length-1; i>=0; --i){
        var ele = arr[i];
        if(ele[key] === value){
            return ele
        }
    }
    return null;
}

function getDscFromList(target, name){
    for( var i = target.length - 1; i >= 0; i-- ){
        var obj = target[ i ];
        if(obj.name == name){
            return obj;
        }
    }
    return null;
}

function getOrderedObjStr(obj){
    var keys = Object.keys( obj );
    keys.sort();
    var key = keys[ 0 ];
    var out = "{" + getSimpleJSONStr( key, obj[ key ] );
    for(var i=1,len=keys.length; i<len; ++i){
        key = keys[i]
        out += ",\n" + getSimpleJSONStr( key, obj[ key ] );
    }
    out += "}";
    return out;
}

function getOrderedResourceStr(obj){
    var out = '{"groups":'
    out += getOrderedGroupStr(obj.groups, 'name')
    out += ','+"\n"+'"resources":'
    out += getOrderedGroupStr(obj.resources, 'name')
    out += '}'
    return out;
}
function getOrderedGroupStr(list, ordKey){
    var ele = list[0]
    if(!ele) return '[\n]'
    list.sort(function(a,b){
        return a[ordKey].localeCompare(b[ordKey])
    })
    ele = list[0]//重新排序过了
    var out = "[\n"+getOrderedObjStr(ele)
    for(var i=1,len=list.length; i<len; ++i){
        ele = list[i]
        out += ",\n" + getOrderedObjStr(ele)
    }
    out += ']'
    return out
}

function getSimpleJSONStr(key, value){
    return '"'+key+'":"'+value+'"'
}

function writeFile(path, content, log, options){
    fs.writeFile(path, content, 'utf8', function(err){
        if(err){
            warn(err)
        }else{
            console.log(log);
        }
    })
}

function getDescribeObj(url, pathObj){
    return {name:pathObj.name, type:getFileType(pathObj.ext), url:url};
}

function tranceUrl(orgUrl){
    var url = orgUrl.split(RESOURCE_ROOT).pop();
    return url.replace(/\\/g, '/')
}
function tranceFileName(org){
    return org.replace(/\./g, '_')
}

function getFileType(ext){
    ext = ext.split('.').pop()
    switch(ext){
        case 'png':
        case 'jpg':
            return 'image'
        case 'fui':
        case 'dbbin':
        case 'zip':
        case 'ske':
        case 'sked':
        case 'cfg':
            return 'bin'
        case 'fnt':
            return 'font'
        case 'json':
            return 'json'
        case 'mp3':
            return 'sound'
        default:
            return ext
    }
}

//resource下的单独文件不处理
function walkResourceRoot(){
    fs.readdir(RESOURCE_ROOT, function(rootErr, rootFiles){
        if(rootErr){
            warn( rootErr );
        }else{
            var len = rootFiles.length;
            var cntObj = [0]
            for( var i = 0; i < len; i++ ){
                var rtFile = rootFiles[i];
                if(rtFile == 'lang'){//多语言只处理对应语言下的资源
                    var langRoot = path.join( RESOURCE_ROOT, rtFile, LANG_FOLDER )
                    fs.stat(langRoot, function(lErr, lSt){
                        if(lErr){
                            warn('!!!!!!!lang folder is missing:'+langRoot)
                        }else{
                            recursiveFiles( langRoot, cntObj, true )
                        }
                    })
                }else {
                    var child = path.join( RESOURCE_ROOT, rtFile )
                    recursiveFiles( child, cntObj, false )
                }
            }
        }
    })
}

function recursiveFiles(file, cntObj, careFile){
    fs.stat(file, function(sErr, st){
        if(sErr){
            warn(sErr)
        }else{
            if(st.isDirectory()){
                fs.readdir(file, function(fErr, children){
                    if(fErr){
                        warn( fErr );
                    }else{
                        var len = children.length;
                        for(var i=0; i<len; i++){
                            recursiveFiles(path.join(file,children[i]), cntObj, true);
                        }
                    }
                })
            }else if(careFile){
                checkFile(file, cntObj)
            }
        }
    })
}

function checkFile(file, cntObj){
    ++cntObj[0]
    var hash = crypto.createHash('md5')
    var rs = fs.createReadStream(file)
    rs.on('data', function(chunk){
        hash.update(chunk)
    })
    rs.on('end', function(){
        addMap(_newVMap, tranceUrl(file), hash.digest('hex'))
        finishFileCheck( cntObj );
    })
}



function addMap(map, key, value){
    if(hasProperty( map, key )){
        warn('repeat key')
    }
    map[key] = value
}

function checkMap(map, key, value){
    if(hasProperty(map,key)){
        return map[key] == value
    }else{
        console.warn('no key')
        return false
    }
}

function hasProperty(obj, key){
    return typeof obj[key] !== 'undefined'
}

function warn(content){
    console.warn( content );
}

